package com.starxg.m3u8.download;

import java.io.File;
import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.util.Collection;

import com.starxg.m3u8.exception.M3U8Exception;
import com.starxg.m3u8.parser.M3U8;
import com.starxg.m3u8.parser.M3U8Item;
import com.starxg.m3u8.parser.M3U8ItemStatus;
import com.starxg.m3u8.parser.M3U8Key;
import com.starxg.m3u8.utils.EncryptUtils;
import com.starxg.m3u8.utils.ThreadPoolUtils;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.ObjectUtils;
import com.starxg.m3u8.config.ApplicationConfig;

import lombok.extern.slf4j.Slf4j;

@Slf4j
public class M3U8Merger {

    private Collection<M3U8Item> items;
    private File savePath;
    private M3U8 m3u8;

    /**
     * 合并ts文件
     *
     * @param m3u8
     *            m3u8
     *
     * @param items
     *            ts
     * @param savePath
     *            最终文件保存位置
     */
    public M3U8Merger(M3U8 m3u8, Collection<M3U8Item> items, File savePath) {
        this.items = items;
        this.savePath = savePath;
        this.m3u8 = m3u8;
    }

    public void start(M3U8DownloadCallback<M3U8Merger> callback) {
        log.info("开始合并分片");
        callback.before(this);
        ThreadPoolUtils.execute(() -> {
            try (FileChannel out = new RandomAccessFile(savePath, "rw").getChannel();) {
                merge(out, callback);
            } catch (Exception e) {
                callback.failed(e);
            } finally {
                callback.completed();
            }
        });
    }

    private void merge(FileChannel out, M3U8DownloadCallback<M3U8Merger> callback) {
        boolean autoDeleteTs = ApplicationConfig.getInstance().getApp().isAutoDeleteTs();
        for (M3U8Item item : items) {

            if (item.getStatus() != M3U8ItemStatus.SUCCEEDED) {
                callback.part(item, new M3U8Exception("文件 [" + item.getName() + "] 状态不是 `下载成功` 跳过合并"));
                continue;
            }

            File file = item.getSavePath();
            if (!file.exists()) {
                callback.part(item, new M3U8Exception("文件 [" + file.getName() + "] 不存在，跳过合并。"));
                continue;
            }

            try (FileChannel in = new RandomAccessFile(item.getSavePath(), "r").getChannel()) {
                M3U8Key key = ObjectUtils.defaultIfNull(item.getKey(), m3u8.getKey());
                if (key != null) {
                    ByteBuffer buffer = EncryptUtils.decrypt(key.getKey(), in, key.getIv());
                    out.write(buffer);
                } else {
                    in.transferTo(0, in.size(), out);
                }
                callback.part(item);
            } catch (Exception e) {
                callback.part(item, e);
            }

            if (autoDeleteTs) {
                log.info("[{}] 合并成功 自动删除源文件:[{}]", item.getName(), file.getAbsolutePath());
                if (!FileUtils.deleteQuietly(file)) {
                    log.info("自动删除源文件 [{}] 失败", item.getName(), file.getAbsolutePath());
                }
            }
        }
    }

}
